using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using Tool;

namespace SerialPortCommunicationProject
{

    /// <summary>
    /// NewDeviceWindow.xaml 的交互逻辑
    /// </summary>
    public partial class NewDeviceWindow : Window
    {
        private Database database = Database.GetInstance();
        private ObservableCollection<Command> commands;

        //data source
        List<CommunicationMode> commModeList = new List<CommunicationMode>() {
                new CommunicationMode(){Name="串口", Mode=CommunicationModeEnum.SerialPort},
                new CommunicationMode(){Name="Socket(TCP)", Mode=CommunicationModeEnum.SocketTcp},
            };
        int[] baudRates = new int[] { 600, 1200, 2400, 4800, 9600, 19200, 38400, 115200 };
        int[] dataBits = new int[] { 5, 6, 7, 8 };
        List<ParityBits> parityBitsList = new List<ParityBits>()
            {
                new ParityBits(){Name="None", Code=Parity.None},
                new ParityBits(){Name="Odd", Code=Parity.Odd},
                new ParityBits(){Name="Even", Code=Parity.Even},
                new ParityBits(){Name="Mark", Code=Parity.Mark},
                new ParityBits(){Name="Space", Code=Parity.Space},
            };
        List<StopBitsClass> stopBitsList = new List<StopBitsClass>()
            {
                new StopBitsClass(){Name="1", Code=StopBits.One},
                new StopBitsClass(){Name="1.5", Code=StopBits.OnePointFive},
                new StopBitsClass(){Name="2", Code=StopBits.Two}
            };
        string[] cOrS = new string[] { "TCP Client", "TCP Server" };
        List<string> ipList = new List<string>()
            {
                "127.0.0.1",
                "0.0.0.0"
            };

        public string StopBitsToString(StopBits stopBits)
        {
            string value = "1";
            switch (stopBits)
            {
                case StopBits.One: break;
                case StopBits.Two: value = "2"; break;
                case StopBits.OnePointFive: value = "1.5"; break;
            }
            return value;
        }

        public string ParityToString(Parity parity)
        {
            string value = "None";
            switch (parity)
            {
                case Parity.None: break;
                case Parity.Odd:
                    value = "Odd";
                    break;
                case Parity.Even:
                    value = "Even";
                    break;
                case Parity.Mark:
                    value = "Mark";
                    break;
                case Parity.Space:
                    value = "Space";
                    break;
            }
            return value;
        }

        
        public NewDeviceWindow()
        {
            InitializeComponent();
            InitializeShowData();
            if (App.CurrentDevice.CommMode == StaticData.SOCKETTCP)
            {
                if (!App.CurrentDevice.IsServer)
                {
                    //默认为Client 则可编辑IP
                    CbBox_IpAddress.IsEditable = true;
                }
                else
                {
                    CbBox_IpAddress.IsEditable = false;
                }
            }
            
            if (App.CurrentDevice.Name == "+")
            {
                TbBox_DeviceName.Text = string.Empty;
            }
            else
            {
                TbBox_DeviceName.Text = App.CurrentDevice.Name;
            }
            // 绑定当前设备信息
            CbBox_SerialPort.Text = App.CurrentDevice.PortName;
            CbBox_BaudRate.Text=App.CurrentDevice.BaudRate.ToString();
            CbBox_ParityBits.Text = App.ParityToString(App.CurrentDevice.Parity);
            CbBox_DataBits.Text = App.CurrentDevice.DataBits.ToString(); ;
            CbBox_StopBits.Text = App.StopBitsToString(App.CurrentDevice.StopBits);
            CbBox_IpAddress.Text = App.CurrentDevice.Ip;
            TBox_Port.Text = App.CurrentDevice.Port.ToString(); 
            CbBox_CorS.Text = App.IsServerToString(App.CurrentDevice.IsServer);
            CbBox_Encoding.Text = App.CurrentDevice.Encoding;

            commands = App.CurrentDevice.Commands;
            commands.Last().Name = "双击添加";
            lBox_Commands.ItemsSource = commands;
            lBox_Commands.DisplayMemberPath = "Name";
            lBox_Commands.SelectedIndex = 0;                                       
        }

        private void InitializeSerialPort()
        {
            int[] baudRates = new int[] { 600, 1200, 2400, 4800, 9600, 19200, 38400, 115200 };
            int[] dataBits = new int[] { 5, 6, 7, 8 };
            List<ParityBits> parityBitsList = new List<ParityBits>()
            {
                new ParityBits(){Name="None", Code=Parity.None},
                new ParityBits(){Name="Odd", Code=Parity.Odd},
                new ParityBits(){Name="Even", Code=Parity.Even},
                new ParityBits(){Name="Mark", Code=Parity.Mark},
                new ParityBits(){Name="Space", Code=Parity.Space},
            };
            List<StopBitsClass> stopBitsList = new List<StopBitsClass>()
            {
                new StopBitsClass(){Name="1", Code=StopBits.One},
                new StopBitsClass(){Name="1.5", Code=StopBits.OnePointFive},
                new StopBitsClass(){Name="2", Code=StopBits.Two}
            };
            this.CbBox_SerialPort.ItemsSource = SerialPort.GetPortNames();
            this.CbBox_CommMode.ItemsSource = commModeList;
            this.CbBox_CommMode.DisplayMemberPath = "Name";
            this.CbBox_BaudRate.ItemsSource = baudRates;
            this.CbBox_DataBits.ItemsSource = dataBits;
            this.CbBox_ParityBits.ItemsSource = parityBitsList;
            this.CbBox_ParityBits.DisplayMemberPath = "Name";
            this.CbBox_StopBits.ItemsSource = stopBitsList;
            this.CbBox_StopBits.DisplayMemberPath = "Name";
        }

        private void InitializeSocketTcp()
        {
            string[] cOrS = new string[] { "TCP Client", "TCP Server" };
            List<string> ipList = new List<string>()
            {
                "127.0.0.1",
                "0.0.0.0"
            };
            this.CbBox_CorS.ItemsSource = cOrS;
            this.CbBox_IpAddress.ItemsSource = ipList;
        }

        private void InitializeShowData()
        {
            if (App.CurrentDevice == null)
            {
                return;
            }
            List<string> commModeList = new List<string>() { "串口", "Socket(TCP)" };
            CbBox_CommMode.ItemsSource = commModeList;

            TbBox_DeviceName.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = new Device() });
            CbBox_Encoding.SetBinding(ComboBox.TextProperty, new Binding("Encoding") { Source = App.CurrentDevice });

            InitializeSerialPort();
            InitializeSocketTcp();

            CbBox_CommMode.SetBinding(ComboBox.TextProperty, new Binding("CommMode") { Source = App.CurrentDevice });
            CbBox_BaudRate.SetBinding(ComboBox.TextProperty, new Binding("BaudRate") { Source = App.CurrentDevice });
            CbBox_DataBits.SetBinding(ComboBox.TextProperty, new Binding("DataBits") { Source = App.CurrentDevice });
            CbBox_ParityBits.SetBinding(ComboBox.TextProperty, new Binding("Parity") { Source = App.CurrentDevice, Converter = new ParityConverter() });
            CbBox_StopBits.SetBinding(ComboBox.TextProperty, new Binding("StopBits") { Source = App.CurrentDevice, Converter = new StopBitsConverter() });
            CbBox_CorS.SetBinding(ComboBox.TextProperty, new Binding("IsServer") { Source = App.CurrentDevice, Converter = new IsServerConverter() });
            CbBox_IpAddress.SetBinding(ComboBox.TextProperty, new Binding("Ip") { Source = App.CurrentDevice });
            TBox_Port.SetBinding(TextBox.TextProperty, new Binding("Port") { Source = App.CurrentDevice });
        }

        private void CbBox_SerialPort_DropDownOpened(object sender, EventArgs e)
        {
            this.CbBox_SerialPort.ItemsSource = SerialPort.GetPortNames();
        }

        private void CbBox_LocalAddress_DropDownOpened(object sender, EventArgs e)
        {
            if (CbBox_CorS.SelectedIndex == 1)//Server
            {
                this.CbBox_IpAddress.ItemsSource = App.GetServerIpAddresses();
            }
        }

        private void CbBox_CorS_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox comboBox = sender as ComboBox;
            if (comboBox.SelectedIndex == 0)//Client
            {
                this.TBlock_IP.Text = "远程主机地址";
                this.TBlock_Port.Text = "远程主机端口";
                this.CbBox_IpAddress.IsEditable = true;
            }
            else if (comboBox.SelectedIndex == 1)//Server
            {
                this.TBlock_IP.Text = "本地主机地址";
                this.TBlock_Port.Text = "本地主机端口";
                this.CbBox_IpAddress.IsEditable = false;
                this.CbBox_IpAddress.ItemsSource = new List<string>()
                {
                    //针对Server 获取本地主机IP
                    new System.Net.IPAddress( Dns.GetHostAddresses( Dns.GetHostName())[1].GetAddressBytes()).ToString() ,
                    "127.0.0.1",
                    "0.0.0.0"
                };
                this.CbBox_IpAddress.SelectedIndex = 0;
            }
        }

        /// <summary>
        /// 转换
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public CommunicationModeEnum StringToMode(string name)
        {
            CommunicationModeEnum mode = CommunicationModeEnum.SerialPort;
            if (name == "串口")
            {

            }
            else if (name == "Socket(TCP)")
            {
                mode = CommunicationModeEnum.SocketTcp;
            }
            return mode;
        }

        private void lBox_Commands_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var listBox = sender as ListBox;
            int index = listBox.SelectedIndex;
            if (index < 0)
            {
                return;
            }
            App.CurrentCommand = App.CurrentDevice.Commands[index];
            var newCommandWindow = new NewCommandWindow(App.CurrentDevice, TbBox_DeviceName.Text);
            newCommandWindow.Owner = this;
            newCommandWindow.ShowDialog();
        }

        private void DeleteItem_Click(object sender, RoutedEventArgs e)
        {
            int index = this.lBox_Commands.SelectedIndex;
            if(index<0 || index == commands.Count - 1)
            {
                return;
            }
            commands.RemoveAt(index);
        }

        private void DeleteAll_Click(object sender, RoutedEventArgs e)
        {
            int index = this.lBox_Commands.SelectedIndex;
            if (index < 0 || index == commands.Count - 1)
            {
                return;
            }
            while (commands.Count > 1)
            {
                commands.RemoveAt(commands.Count - 2);
            }

        }

        private bool IsRepetition(string newName)
        {
            bool result = false;
            foreach(Device device in App.LstDevices)
            {
                if(device.Name== newName)
                {
                    MessageBox.Show("设备名称重复!");
                    TbBox_DeviceName.Focus();
                    result = true;
                }
            }
            return result;
        }

        private void AddDevice(bool isNew)
        {
            int.TryParse(CbBox_BaudRate.Text, out int baudRate);
            int.TryParse(CbBox_DataBits.Text, out int dataBits);
            ObservableCollection<Command> tempList = new ObservableCollection<Command>();
            foreach (Command c in commands)
            {
                if (c != commands.Last())
                {
                    tempList.Add(c);
                }
                else
                {
                    tempList.Add(new Command() { Name = "+" });
                }
            }
            Device newDevice = new Device()
            {
                Name = TbBox_DeviceName.Text,
                CommMode = CbBox_CommMode.Text,
                Encoding = CbBox_Encoding.Text,
                Commands = tempList
            };
            if (CbBox_CommMode.Text == StaticData.SERIALPORT)
            {
                newDevice.PortName = CbBox_SerialPort.Text;
                newDevice.BaudRate = baudRate;
                newDevice.DataBits = dataBits;
                newDevice.Parity = App.StringToParity(CbBox_ParityBits.Text);
                newDevice.StopBits = App.StringToStopBits(CbBox_StopBits.Text);

                newDevice.Ip = null;
                newDevice.Port = 0;
                newDevice.IsServer = false;

            }
            else if(CbBox_CommMode.Text == StaticData.SOCKETTCP)
            {
                newDevice.Ip = CbBox_IpAddress.Text;
                int.TryParse(TBox_Port.Text, out int port);
                newDevice.Port = port;
                newDevice.IsServer = App.StringToIsServer(CbBox_CorS.Text);

                newDevice.PortName = null;
                newDevice.BaudRate = 0;
                newDevice.DataBits = 0;
                newDevice.Parity = 0;
                newDevice.StopBits = 0;
            }
            if (isNew)
            {
                App.LstDevices.Insert(App.LstDevices.Count - 1, newDevice);
                database.AddDevice(newDevice);
            }
            else
            {
                int index = App.LstDevices.IndexOf(App.CurrentDevice);
                App.LstDevices.Remove(App.CurrentDevice);
                App.LstDevices.Insert(index, newDevice);
                
                database.ModifyDevice(App.CurrentDevice,TbBox_DeviceName.Text);
                App.CurrentDevice = newDevice;
            }


        }

        private void Btn_Save_Click(object sender, RoutedEventArgs e)
        {

            if (App.CurrentDevice.Name == "+")
            {
                // 判断是否名称重复
                if (IsRepetition(TbBox_DeviceName.Text))
                {
                    //MessageBox.Show("设备名称重复!");
                    //TbBox_DeviceName.Focus();
                    return;
                }
                else
                {
                    AddDevice(true);
                    this.Close();
                }
            }
            else if(TbBox_DeviceName.Text.Replace(" ","").Equals(string.Empty))
            {
                MessageBox.Show("设备名称不能为空!");
                TbBox_DeviceName.Text = string.Empty;
            }
            else
            {
                if (!App.CurrentDevice.Name.Equals(TbBox_DeviceName.Text) && IsRepetition(TbBox_DeviceName.Text))
                {   
                    return;
                }
                // 若未改变设备名称或者不存在修改后的设备名称重复，则更改设备参数，并更新数据库
                AddDevice(false);
                this.Close();
            }
        }

        private void Btn_Cancel_Click(object sender, RoutedEventArgs e)
        {
            //if (App.CurrentDevice.Commands.Last().Name == "双击添加")
            //{
            //    App.CurrentDevice.Commands.Last().Name = "+";
            //}
            this.Close();
        }

        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    try
                    {
                        this.DragMove();
                    }
                    finally
                    { }
                }));
            }
        }
    }
}

